home *** CD-ROM | disk | FTP | other *** search
- #define fatal ar_fatal
- #define error ar_error
- #define progname ar_progname
- #define main ar_main
- #define concat ar_concat
- #define mywrite ar_mywrite
- #define perror_with_name ar_perror_with_name
- #define pfatal_with_name ar_pfatal_with_name
-
- /* ar.c - Archive modify and extract.
- Copyright (C) 1988, 1990 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include <stdio.h>
- #include <ar.h>
- #include <errno.h>
- #include <sys/types.h>
-
- #if !defined(A_OUT) && !defined(MACH_O)
- #define A_OUT
- #endif
-
- #ifdef A_OUT
- #ifdef COFF_ENCAPSULATE
- #include "a.out.encap.h"
- #else
- #include <a.out.h>
- #endif
- #endif
-
- #ifdef MACH_O
- #ifndef A_OUT
- #include <nlist.h>
- #endif
- #include <sys/loader.h>
- #endif
-
- #if !defined(USG) || defined(hpux)
- #define HAVE_FCHMOD
- #ifndef THINK_C
- #define HAVE_FSYNC
- #endif
- #define HAVE_RENAME
- #endif /* !USG || hpux */
-
- #ifdef USG
- #include <time.h>
- #include <fcntl.h>
- #else
- #include <sys/file.h>
- #include <sys/time.h>
- #endif
-
- #ifdef __GNUC__
- #define alloca __builtin_alloca
- #else
- # ifdef sparc
- # include <alloca.h>
- # else
- #ifndef THINK_C
- char *alloca ();
- #endif
- # endif
- #endif
-
- #ifdef USG
- #define bcopy(source, dest, size) memcpy((dest), (source), (size))
- #define bcmp(a, b, size) memcmp((a), (b), (size))
- #define bzero(s, size) memset((s), 0, (size))
- #endif
-
- /* Locking is normally disabled because fcntl hangs on the Sun
- and it isn't supported properly across NFS anyway. */
- #ifdef LOCKS
- /* You might need to compile with -I/usr/include/sys if your fcntl.h
- isn't in /usr/include (which is where it should be according to POSIX). */
- #include <fcntl.h>
- #endif
-
- /* This structure is used internally to represent the info
- on a member of an archive. This is to make it easier to change format. */
-
- struct member_desc
- {
- /* Name of member. */
- char *name;
-
- /* The following fields are stored in the member header as decimal or octal
- numerals, but in this structure they are stored as machine numbers. */
- int mode; /* Protection mode from member header. */
- long int date; /* Last modify date as stored in member header. */
- unsigned int size; /* Bytes of member's data, from member header. */
- int uid, gid; /* UID and GID fields copied from member header. */
- unsigned int offset;/* Offset in archive of the header of this member. */
- unsigned int data_offset;/* Offset of first data byte of the member. */
-
- /* The next field does not describe where the member was in the
- old archive, but rather where it will be in the modified archive.
- It is set up by write_archive. */
- unsigned int new_offset; /* Offset of this member in new archive */
-
- /* Symdef data for member. Used only for files being inserted. */
- struct symdef *symdefs;
- unsigned int nsymdefs; /* Number of entries of symdef data. */
- unsigned int string_size; /* Size of strings needed by symdef data. */
- };
-
- /* Each symbol is recorded by something like this. */
-
- struct symdef
- {
- union
- {
- unsigned long int stringoffset;
- char *name;
- } s;
- unsigned long int offset;
- };
-
- /* Nonzero means it's the name of an existing member;
- position new or moved files with respect to this one. */
-
- char *posname;
-
- /* How to use `posname':
- POS_BEFORE means position before that member.
- POS_AFTER means position after that member.
- POS_DEFAULT if position by default; then `posname' should also be zero. */
-
- enum { POS_DEFAULT, POS_BEFORE, POS_AFTER } postype;
-
- /* Nonzero means describe each action performed. */
-
- int verbose;
-
- /* Nonzero means don't warn about creating the archive file if necessary. */
-
- int silent_create;
-
- /* Nonzero means don't replace existing members whose
- dates are more recent than the corresponding files. */
-
- int newer_only;
-
- /* Nonzero means preserve dates of members when extracting them. */
-
- int preserve_dates;
-
- /* Operation to be performed. */
-
- #define DELETE 1
- #define REPLACE 2
- #define PRINT_TABLE 3
- #define PRINT_FILES 4
- #define EXTRACT 5
- #define MOVE 6
- #define QUICK_APPEND 7
-
- int operation;
-
- /* Name of archive file. */
-
- char *archive;
-
- /* Descriptor on which we have locked the original archive file,
- or -1 if this has not been done. */
-
- int lock_indesc;
-
- /* Pointer to tail of `argv', at first subfile name argument,
- or zero if no such were specified. */
-
- char **files;
-
- /* Nonzero means write a __.SYMDEF member into the modified archive. */
-
- int symdef_flag;
-
- /* Nonzero means __.SYMDEF member exists in old archive. */
-
- int symdef_exists;
-
- /* Nonzero means don't update __.SYMDEF unless the flag was given. */
-
- int ignore_symdef;
-
- /* Total number of symdef entries we will have. */
-
- unsigned long int nsymdefs;
-
- /* Symdef data from old archive (set up only if we need it) */
-
- struct symdef *old_symdefs;
-
- /* Number of symdefs in remaining in old_symdefs. */
-
- unsigned int num_old_symdefs;
-
- /* Number of symdefs old_symdefs had when it was read in. */
-
- unsigned long int original_num_symdefs;
-
- /* String table from old __.SYMDEF member. */
-
- char *old_strings;
-
- /* Size of old_strings */
-
- unsigned long int old_strings_size;
-
- /* String table to be written into __.SYMDEF member. */
-
- char *new_strings;
-
- /* Size of new_strings */
-
- unsigned long int new_strings_size;
-
- /* An archive map is a chain of these structures.
- Each structure describes one member of the archive.
- The chain is in the same order as the members are. */
-
- struct mapelt
- {
- struct member_desc info;
- struct mapelt *next;
- };
-
- struct mapelt *maplast;
-
- /* If nonzero, this is the map-element for the __.SYMDEF member
- and we should update the time of that member just before finishing. */
-
- struct mapelt *symdef_mapelt;
-
- /* Header that we wrote for the __.SYMDEF member. */
-
- struct ar_hdr symdef_header;
-
- /* Name this program was run with. */
- char *program_name;
-
- #ifndef xmalloc
- char *xmalloc (), *xrealloc ();
- void free ();
- #endif
-
- void add_to_map (), delete_from_map ();
- int insert_in_map ();
- void print_descr ();
- char *concat ();
- void scan ();
- void extract_members ();
- void extract_member ();
- void print_contents ();
- void write_symdef_member ();
- void two_operations ();
- void usage (), fatal (), error (), error_with_file ();
- void perror_with_name (), pfatal_with_name ();
- void write_archive ();
- void touch_symdef_member ();
- void update_symdefs ();
- void delete_members (), move_members (), replace_members ();
- void quick_append ();
-
- /* Output BYTES of data at BUF to the descriptor DESC.
- FILE is the name of the file (for error messages). */
-
- void
- mywrite (desc, buf, bytes, file)
- int desc;
- char *buf;
- int bytes;
- char *file;
- {
- register int val;
-
- while (bytes > 0)
- {
- val = write (desc, buf, bytes);
- if (val <= 0)
- perror_with_name (file);
- buf += val;
- bytes -= val;
- }
- }
-
- void
- main (argc, argv)
- int argc;
- char **argv;
- {
- int i;
-
- operation = 0;
- verbose = 0;
- newer_only = 0;
- silent_create = 0;
- posname = 0;
- postype = POS_DEFAULT;
- preserve_dates = 0;
- symdef_flag = 0;
- symdef_exists = 0;
- ignore_symdef = 0;
- symdef_mapelt = 0;
- files = 0;
- lock_indesc = -1;
-
- if (argc < 2)
- usage ("too few command arguments", 0);
-
- {
- char *key = argv[1];
- char *p = key;
- char c;
-
- while (c = *p++)
- {
- switch (c)
- {
- case 'a':
- postype = POS_AFTER;
- break;
-
- case 'b':
- postype = POS_BEFORE;
- break;
-
- case 'c':
- silent_create = 1;
- break;
-
- case 'd':
- if (operation)
- two_operations ();
-
- operation = DELETE;
- break;
-
- case 'i':
- postype = POS_BEFORE;
- break;
-
- case 'l':
- break;
-
- case 'm':
- if (operation)
- two_operations ();
- operation = MOVE;
- break;
-
- case 'o':
- preserve_dates = 1;
- break;
-
- case 'p':
- if (operation)
- two_operations ();
- operation = PRINT_FILES;
- break;
-
- case 'q':
- if (operation)
- two_operations ();
- operation = QUICK_APPEND;
- break;
-
- case 'r':
- if (operation)
- two_operations ();
- operation = REPLACE;
- break;
-
- case 's':
- symdef_flag = 1;
- break;
-
- case 't':
- if (operation)
- two_operations ();
- operation = PRINT_TABLE;
- break;
-
- case 'u':
- operation = REPLACE;
- newer_only = 1;
- break;
-
- case 'v':
- verbose = 1;
- break;
-
- case 'x':
- if (operation)
- two_operations ();
- operation = EXTRACT;
- break;
- }
- }
-
- }
-
- if (operation == 0 && symdef_flag)
- operation = REPLACE;
-
- if (operation == 0)
- usage ("no operation specified", 0);
-
- i = 2;
-
- if (postype != POS_DEFAULT)
- posname = argv[i++];
-
- archive = argv[i++];
-
- if (i < argc)
- {
- files = &argv[i];
- while (i < argc)
- if (!strcmp (argv[i++], "__.SYMDEF"))
- {
- ignore_symdef = 1;
- break;
- }
- }
-
- switch (operation)
- {
- case EXTRACT:
- extract_members (extract_member);
- break;
-
- case PRINT_TABLE:
- extract_members (print_descr);
- break;
-
- case PRINT_FILES:
- extract_members (print_contents);
- break;
-
- case DELETE:
- if (files != 0)
- delete_members ();
- break;
-
- case MOVE:
- if (files != 0)
- move_members ();
- break;
-
- case REPLACE:
- if (files != 0 || symdef_flag)
- replace_members ();
- break;
-
- case QUICK_APPEND:
- if (files != 0)
- quick_append ();
- break;
-
- default:
- usage ("invalid operation %d", operation);
- }
-
- exit (0);
- }
-
- void
- two_operations ()
- {
- usage ("two different operation switches specified", 0);
- }
-
-
- void
- scan (function, crflag)
- void (*function) ();
- int crflag;
- {
- }
-
-
- void print_modes ();
-
- void
- print_descr (member)
- struct member_desc member;
- {
- char *timestring;
- if (!verbose)
- {
- puts (member.name);
- return;
- }
- print_modes (member.mode);
- timestring = ctime (&member.date);
- printf (" %2d/%2d %6d %12.12s %4.4s %s\n",
- member.uid, member.gid,
- member.size, timestring + 4, timestring + 20,
- member.name);
- }
-
- void
- print_modes (modes)
- int modes;
- {
- putchar (modes & 0400 ? 'r' : '-');
- putchar (modes & 0200 ? 'w' : '-');
- putchar (modes & 0100 ? 'x' : '-');
- putchar (modes & 040 ? 'r' : '-');
- putchar (modes & 020 ? 'w' : '-');
- putchar (modes & 010 ? 'x' : '-');
- putchar (modes & 04 ? 'r' : '-');
- putchar (modes & 02 ? 'w' : '-');
- putchar (modes & 01 ? 'x' : '-');
- }
-
- #define BUFSIZE 1024
-
- void
- extract_member (member, istream)
- struct member_desc member;
- FILE *istream;
- {
- int ncopied = 0;
- FILE *ostream;
-
- fseek (istream, member.data_offset, 0);
- ostream = fopen (member.name, "w");
- if (!ostream)
- {
- perror_with_name (member.name);
- return;
- }
-
- if (verbose)
- printf ("x - %s\n", member.name);
-
- while (ncopied < member.size)
- {
- char buf [BUFSIZE];
- int tocopy = member.size - ncopied;
- int nread;
- if (tocopy > BUFSIZE) tocopy = BUFSIZE;
- nread = fread (buf, 1, tocopy, istream);
- if (nread != tocopy)
- fatal ("file %s not a valid archive", archive);
- fwrite (buf, 1, nread, ostream);
- ncopied += tocopy;
- }
- #ifndef THINK_C
- #ifdef HAVE_FCHMOD
- fchmod (fileno (ostream), member.mode);
- #else
- chmod (member.name, member.mode);
- #endif
- #endif
- if (ferror (ostream) || fclose (ostream) != 0)
- error ("%s: I/O error", member.name);
- #ifndef THINK_C
- if (preserve_dates)
- {
- #ifdef USG
- long tv[2];
- tv[0] = member.date;
- tv[1] = member.date;
- utime (member.name, tv);
- #else
- struct timeval tv[2];
- tv[0].tv_sec = member.date;
- tv[0].tv_usec = 0;
- tv[1].tv_sec = member.date;
- tv[1].tv_usec = 0;
- utimes (member.name, tv);
- #endif
- }
- #endif
- }
-
- void
- print_contents (member, istream)
- struct member_desc member;
- FILE *istream;
- {
- int ncopied = 0;
-
- fseek (istream, member.data_offset, 0);
-
- if (verbose)
- printf ("\n<member %s>\n\n", member.name);
-
- while (ncopied < member.size)
- {
- char buf [BUFSIZE];
- int tocopy = member.size - ncopied;
- int nread;
- if (tocopy > BUFSIZE) tocopy = BUFSIZE;
- nread = fread (buf, 1, tocopy, istream);
- if (nread != tocopy)
- fatal ("file %s not a valid archive", archive);
- fwrite (buf, 1, nread, stdout);
- ncopied += tocopy;
- }
- }
-
- /* Make a map of the existing members of the archive: their names,
- positions and sizes. */
-
- /* If `nonexistent_ok' is nonzero,
- just return 0 for an archive that does not exist.
- This will cause the ordinary supersede procedure to
- create a new archive. */
-
- struct mapelt *
- make_map (nonexistent_ok)
- int nonexistent_ok;
- {
- struct mapelt mapstart;
- mapstart.next = 0;
- maplast = &mapstart;
- scan (add_to_map, nonexistent_ok);
- return mapstart.next;
- }
-
- void
- add_to_map (member)
- struct member_desc member;
- {
- struct mapelt *mapelt = (struct mapelt *) xmalloc (sizeof (struct mapelt));
- mapelt->info = member;
- mapelt->info.name = concat (mapelt->info.name, "", "");
- maplast->next = mapelt;
- mapelt->next = 0;
- maplast = mapelt;
- }
-
- /* Return the last element of the specified map. */
-
- struct mapelt *
- last_mapelt (map)
- struct mapelt *map;
- {
- struct mapelt *tail = map;
- while (tail->next) tail = tail->next;
- return tail;
- }
-
- /* Return the element of the specified map which precedes elt. */
-
- struct mapelt *
- prev_mapelt (map, elt)
- struct mapelt *map, *elt;
- {
- struct mapelt *tail = map;
- while (tail->next && tail->next != elt)
- tail = tail->next;
- if (tail->next) return tail;
- return 0;
- }
-
- /* Return the element of the specified map which has the specified name. */
-
- struct mapelt *
- find_mapelt_noerror (map, name)
- struct mapelt *map;
- register char *name;
- {
- register struct mapelt *tail;
- unsigned int len = strlen (name);
- int dot_o = name[len - 2] == '.' && name[len - 1] == 'o';
-
- for (tail = map; tail != 0; tail = tail->next)
- {
- if (tail->info.name == 0)
- continue;
- if (!strncmp (tail->info.name, name, 13))
- {
- unsigned int eltlen = strlen (tail->info.name);
- if (len <= 13 || eltlen <= 13)
- return tail;
- else
- {
- char *p = tail->info.name + 13;
- if (dot_o && p[0] == '.' && p[1] == 'o' && p[2] == '\0')
- return tail;
- else if (!strncmp (p, name + 13,
- (len > eltlen ? len : eltlen) - 13))
- return tail;
- }
- }
- }
-
- return 0;
- }
-
- struct mapelt *
- find_mapelt (map, name)
- struct mapelt *map;
- char *name;
- {
- register struct mapelt *found = find_mapelt_noerror (map, name);
- if (found == 0)
- error ("no member named `%s'", name);
- return found;
- }
-
- /* Write a new archive file from a given map. */
- /* When a map is used as the pattern for a new archive,
- each element represents one member to put in it, and
- the order of elements controls the order of writing.
-
- Ordinarily, the element describes a member of the old
- archive, to be copied into the new one.
-
- If the `offset' field of the element's info is 0,
- then the element describes a file to be copied into the
- new archive. The `name' field is the file's name.
-
- If the `name' field of an element is 0, the element is ignored.
- This makes it easy to specify deletion of archive members.
-
- Every operation that will eventually call `write_archive'
- should call `lock_for_update' before beginning
- to do any I/O on the archive file.
- */
-
- void lock_for_update()
- {
- }
-
- char *make_tempname ();
- void copy_out_member ();
-
- void
- write_archive (map, appendflag)
- struct mapelt *map;
- int appendflag;
- {
- char *tempname = make_tempname (archive);
- int outdesc;
- char *outname;
- struct mapelt *tail;
-
- /* Now open the output. */
-
- if (!appendflag)
- {
- /* Updating an existing archive normally.
- Write output as TEMPNAME and rename at the end.
- There can never be two invocations trying to do this at once,
- because of the lock made on the old archive file. */
-
- outdesc = open (tempname, O_WRONLY | O_CREAT, 0666);
- if (outdesc < 0)
- pfatal_with_name (tempname);
- outname = tempname;
- mywrite (outdesc, ARMAG, SARMAG, outname);
- }
- else
- {
- /* Fast-append to existing archive. */
-
- outdesc = open (archive, O_WRONLY | O_APPEND, 0);
- if (outdesc < 0)
- pfatal_with_name (archive);
- outname = archive;
- }
-
- /* If archive has or should have a __.SYMDEF member,
- compute the contents for it. */
-
- if (symdef_flag || symdef_exists)
- {
- {
- struct mapelt *this = (struct mapelt *)
- xmalloc (sizeof (struct mapelt));
- this->info.name = "__.SYMDEF";
- this->info.offset = SARMAG;
- this->info.data_offset = SARMAG + sizeof (struct ar_hdr);
- this->info.new_offset = 0;
- this->info.date = 0;
- this->info.size = 0;
- this->info.uid = 0;
- this->info.gid = 0;
- this->info.mode = 0666;
- this->info.symdefs = 0;
- this->info.nsymdefs = 0;
- this->info.string_size = 0;
- this->next = map;
- map = this;
- original_num_symdefs = 0;
- old_strings_size = 0;
- }
-
- update_symdefs (map, 0);
- }
-
- /* Copy the members into the output, either from the old archive
- or from specified files. */
-
- for (tail = map; tail != 0; tail = tail->next)
- {
- if ((symdef_flag || symdef_exists) && tail->info.name
- && !strcmp (tail->info.name, "__.SYMDEF")
- #if 0
- && tail->info.date==0
- #endif
- )
- write_symdef_member (tail, map, outdesc, outname);
- else
- copy_out_member (tail, 0, outdesc, outname);
- }
-
- if (symdef_mapelt != 0)
- {
- /* Check for members whose data offsets weren't
- known when the symdef member was first written. */
- int doneany = 0;
- for (tail = map; tail != 0; tail = tail->next)
- if (tail->info.offset == 0)
- {
- /* Fix up the symdefs. */
- register unsigned int i;
- for (i = 0; i < tail->info.nsymdefs; ++i)
- tail->info.symdefs[i].offset = tail->info.new_offset;
- doneany = 1;
- }
- if (doneany)
- {
- /* Some files had bad symdefs; rewrite the symdef member. */
- lseek (outdesc, symdef_mapelt->info.offset, 0);
- write_symdef_member (symdef_mapelt, map, outdesc, outname);
- }
- }
-
- /* Mark the __.SYMDEF member as up to date. */
-
- if (symdef_mapelt != 0)
- touch_symdef_member (outdesc, outname);
-
- /* Install the new output under the intended name. */
-
- #ifdef HAVE_FSYNC
- fsync (outdesc);
- #endif
- close (outdesc);
- }
-
- void
- header_from_map (header, mapelt)
- struct ar_hdr *header;
- struct mapelt *mapelt;
- {
- unsigned int namelen;
-
- /* Zero the header, then store in the data as text. */
- bzero ((char *) header, sizeof (*header));
-
- strncpy (header->ar_name, mapelt->info.name, sizeof (header->ar_name));
- namelen = strlen (mapelt->info.name);
- if (namelen >= sizeof (header->ar_name))
- {
- if (mapelt->info.name[namelen - 2] == '.' &&
- mapelt->info.name[namelen - 1] == 'o')
- {
- header->ar_name[sizeof (header->ar_name) - 3] = '.';
- header->ar_name[sizeof (header->ar_name) - 2] = 'o';
- }
- header->ar_name[sizeof (header->ar_name) - 1] = '\0';
- error ("member name `%s' truncated to `%s'",
- mapelt->info.name, header->ar_name);
- }
-
- sprintf (header->ar_date, "%ld", mapelt->info.date);
- sprintf (header->ar_size, "%d", mapelt->info.size);
- sprintf (header->ar_uid, "%d", mapelt->info.uid);
- sprintf (header->ar_gid, "%d", mapelt->info.gid);
- sprintf (header->ar_mode, "%o", mapelt->info.mode);
- strncpy (header->ar_fmag, ARFMAG, sizeof (header->ar_fmag));
-
- /* Change all remaining nulls in the header into spaces. */
- {
- char *end = (char *) &header[1];
- register char *p;
- for (p = (char *) header; p < end; ++p)
- if (*p == '\0')
- *p = ' ';
- }
- }
-
- /* writes to file open on OUTDESC with name OUTNAME. */
- void
- copy_out_member (mapelt, archive_indesc, outdesc, outname)
- struct mapelt *mapelt;
- int archive_indesc;
- int outdesc;
- char *outname;
- {
- struct ar_hdr header;
- int indesc;
-
- if (mapelt->info.name == 0)
- /* This element was cancelled. */
- return;
-
- header_from_map (&header, mapelt);
-
- {
- indesc = open (mapelt->info.name, 0, 0);
- if (indesc < 0)
- {
- perror_with_name (mapelt->info.name);
- return;
- }
- }
-
- mywrite (outdesc, &header, sizeof (header), outname);
-
- if (mapelt->info.data_offset == 0)
- mapelt->info.data_offset = lseek (outdesc, 0L, 1);
-
- {
- char *buf = xmalloc(BUFSIZE);
- int thistime = BUFSIZE;
- while (thistime > 0)
- {
- thistime = read (indesc, buf, BUFSIZE);
- mywrite (outdesc, buf, thistime, outname);
- }
- free(buf);
- }
-
- close (indesc);
-
- if (mapelt->info.size & 1)
- mywrite (outdesc, "\n", 1, outname);
- }
-
- /* Update the time of the __.SYMDEF member; done when we updated
- that member, just before we close the new archive file.
- It is open on OUTDESC and its name is OUTNAME. */
-
- void
- touch_symdef_member (outdesc, outname)
- int outdesc;
- char *outname;
- {
- }
-
- char *
- make_tempname (name)
- char *name;
- {
- return concat (name, "", "_supersede");
- }
-
- void
- delete_members ()
- {
- struct mapelt *map = make_map (0);
- struct mapelt mapstart;
- char **p;
-
- mapstart.info.name = 0;
- mapstart.next = map;
- map = &mapstart;
-
- lock_for_update ();
-
- if (files)
- for (p = files; *p; p++)
- {
- /* If user says to delete the __.SYMDEF member,
- don't make a new one to replace it. */
- if (!strcmp (*p, "__.SYMDEF"))
- symdef_exists = 0;
- delete_from_map (*p, map);
- }
-
- write_archive (map->next, 0);
- }
-
- void
- delete_from_map (name, map)
- char *name;
- struct mapelt *map;
- {
- struct mapelt *this = find_mapelt (map, name);
-
- if (!this) return;
- this->info.name = 0;
- if (verbose)
- printf ("d - %s\n", name);
- }
-
- void
- move_members ()
- {
- struct mapelt *map = make_map (0);
- char **p;
- struct mapelt *after_mapelt;
- struct mapelt mapstart;
- struct mapelt *change_map;
-
- mapstart.info.name = 0;
- mapstart.next = map;
- change_map = &mapstart;
-
- lock_for_update ();
-
- switch (postype)
- {
- case POS_DEFAULT:
- after_mapelt = last_mapelt (change_map);
- break;
-
- case POS_AFTER:
- after_mapelt = find_mapelt (map, posname);
- break;
-
- case POS_BEFORE:
- after_mapelt = prev_mapelt (change_map, find_mapelt (map, posname));
- }
-
- /* Failure to find specified "before" or "after" member
- is a fatal error; message has already been printed. */
-
- if (!after_mapelt) exit (1);
-
- if (files)
- for (p = files; *p; p++)
- {
- if (move_in_map (*p, change_map, after_mapelt))
- after_mapelt = after_mapelt->next;
- }
-
- write_archive (map, 0);
- }
-
- int
- move_in_map (name, map, after)
- char *name;
- struct mapelt *map, *after;
- {
- struct mapelt *this = find_mapelt (map, name);
- struct mapelt *prev;
-
- if (!this) return 0;
- prev = prev_mapelt (map, this);
- prev->next = this->next;
- this->next = after->next;
- after->next = this;
- return 1;
- }
-
- /* Insert files into the archive. */
-
- void
- replace_members ()
- {
- struct mapelt *map = make_map (1);
- struct mapelt mapstart;
- struct mapelt *after_mapelt;
- struct mapelt *change_map;
- char **p;
- int changed;
-
- mapstart.info.name = 0;
- mapstart.next = map;
- change_map = &mapstart;
-
- lock_for_update ();
-
- switch (postype)
- {
- case POS_DEFAULT:
- after_mapelt = last_mapelt (change_map);
- break;
-
- case POS_AFTER:
- after_mapelt = find_mapelt (map, posname);
- break;
-
- case POS_BEFORE:
- after_mapelt = prev_mapelt (change_map, find_mapelt (map, posname));
- }
-
- /* Failure to find specified "before" or "after" member
- is a fatal error; the message has already been printed. */
- if (after_mapelt == 0)
- exit (1);
-
- changed = 0;
- if (files != 0)
- for (p = files; *p != 0; ++p)
- if (insert_in_map (*p, change_map, after_mapelt))
- {
- after_mapelt = after_mapelt->next;
- changed = 1;
- }
-
- change_map = change_map->next;
- if (!changed && (!symdef_flag || symdef_exists))
- /* Nothing changed. */ ;
- else
- write_archive (change_map, 0);
- }
-
- /* Handle the "quick insert" operation. */
-
- void
- quick_append ()
- {
- struct mapelt *map;
- struct mapelt *after;
- struct mapelt mapstart;
- char **p;
-
- mapstart.info.name = 0;
- mapstart.next = 0;
- map = &mapstart;
- after = map;
-
- lock_for_update ();
-
- /* Insert the specified files into the "map",
- but is a map of the inserted files only,
- and starts out empty. */
- if (files)
- for (p = files; *p; p++)
- {
- if (insert_in_map (*p, map, after))
- after = after->next;
- }
-
- /* Append these files to the end of the existing archive file. */
-
- write_archive (map->next, 1);
- }
-
- /* Insert an entry for name NAME into the map MAP after the map entry AFTER.
- Delete an old entry for NAME.
- MAP is assumed to start with a dummy entry, which facilitates
- insertion at the beginning of the list.
- Return 1 if successful, 0 if did nothing because file NAME doesn't
- exist or (optionally) is older. */
-
- int
- insert_in_map (name, map, after)
- char *name;
- struct mapelt *map, *after;
- {
- struct mapelt *old = find_mapelt_noerror (map, name);
- struct mapelt *this;
- if (old)
- /* Delete the old one. */
- old->info.name = 0;
- this = (struct mapelt *) xmalloc (sizeof (struct mapelt));
- this->info.name = name;
- this->info.offset = 0;
- this->info.data_offset = 0;
- this->info.date = 0;
- {
- int fd = open(name, O_RDONLY);
- lseek(fd, 0, SEEK_END);
- this->info.size = tell(fd);
- close(fd);
- }
- this->info.uid = 0;
- this->info.gid = 0;
- this->info.mode = 0;
- /* Always place a __.SYMDEF member first in the archive, regardless
- of any position specifications. */
- if (! strcmp (name, "__.SYMDEF"))
- this->next = map->next, map->next = this;
- else
- this->next = after->next, after->next = this;
-
- if (verbose)
- printf ("%c - %s\n", old == 0 ? 'a' : 'r', this->info.name);
-
- return 1;
- }
-
- /* Apply a function to each of the specified members.
- */
-
- void
- extract_members (function)
- void (*function) ();
- {
- struct mapelt *map;
- FILE *arcstream;
- char **p;
-
- if (!files)
- {
- /* Handle case where we want to operate on every member.
- No need to make a map and search it for this. */
- scan (function, 0);
- return;
- }
-
- arcstream = fopen (archive, "r");
- if (!arcstream)
- fatal ("failure opening archive %s for the second time", archive);
- map = make_map (0);
-
- for (p = files; *p; p++)
- {
- struct mapelt *this = find_mapelt (map, *p);
- if (!this) continue;
- function (this->info, arcstream);
- }
-
- fclose (arcstream);
- }
-
- /* Write the __.SYMDEF member from data in core. OUTDESC and OUTNAME
- are descriptor and name of file to write to. */
-
- void
- write_symdef_member (mapelt, map, outdesc, outname)
- struct mapelt *mapelt;
- struct mapelt *map;
- int outdesc;
- char *outname;
- {
- struct ar_hdr header;
- struct mapelt *mapptr;
- unsigned long int symdefs_size;
-
- if (mapelt->info.name == 0)
- /* This element was cancelled. */
- return;
-
- header_from_map (&header, mapelt);
-
- bcopy (&header, &symdef_header, sizeof header);
-
- mywrite (outdesc, &header, sizeof (header), outname);
-
- /* Write the number of symdefs. */
- symdefs_size = nsymdefs * sizeof (struct symdef);
- mywrite (outdesc, &symdefs_size, sizeof symdefs_size, outname);
-
- /* Write symdefs surviving from old archive. */
- mywrite (outdesc, old_symdefs, num_old_symdefs * sizeof (struct symdef),
- outname);
-
- /* Write symdefs for new members. */
- for (mapptr = map; mapptr != 0; mapptr = mapptr->next)
- if (mapptr->info.nsymdefs != 0)
- write (outdesc, mapptr->info.symdefs,
- mapptr->info.nsymdefs * sizeof (struct symdef));
-
- /* Write the string table size. */
- mywrite (outdesc, &new_strings_size, sizeof new_strings_size, outname);
-
- /* Write the string table. */
- mywrite (outdesc, new_strings, new_strings_size, outname);
-
- if (mapelt->info.size & 1)
- mywrite (outdesc, "", 1, outname);
- }
-
- /* Read various information from the header of an object file.
- Return 0 for failure or 1 for success. */
-
- int
- read_header_info (mapelt, desc, offset, syms_offset, syms_size, strs_offset, strs_size)
- struct mapelt *mapelt;
- int desc;
- long int offset;
- long int *syms_offset;
- unsigned int *syms_size;
- long int *strs_offset;
- unsigned int *strs_size;
- {
- #ifdef A_OUT
- {
- struct exec hdr;
-
- lseek (desc, offset, 0);
- #ifdef HEADER_SEEK_FD
- HEADER_SEEK_FD (desc);
- #endif
-
- if (read (desc, (char *) &hdr, sizeof hdr) == sizeof hdr && !N_BADMAG(hdr))
- {
- *syms_offset = N_SYMOFF (hdr);
- *syms_size = hdr.a_syms;
- *strs_offset = N_STROFF (hdr);
- lseek (desc, N_STROFF (hdr) + offset, 0);
- if (read (desc, (char *) strs_size, sizeof *strs_size) != sizeof *strs_size)
- {
- error_with_file ("failure reading string table size in ", mapelt);
- return 0;
- }
- return 1;
- }
- }
- #endif
-
- #ifdef MACH_O
- {
- struct mach_header mach_header;
- struct load_command *load_command;
- struct symtab_command *symtab_command;
- char *hdrbuf;
- int cmd, symtab_seen;
-
- lseek (desc, offset, 0);
- if (read (desc, (char *) &mach_header, sizeof mach_header) == sizeof mach_header
- && mach_header.magic == MH_MAGIC)
- {
- hdrbuf = xmalloc (mach_header.sizeofcmds);
- if (read (desc, hdrbuf, mach_header.sizeofcmds) != mach_header.sizeofcmds)
- {
- error_with_file ("failure reading load commands of ", mapelt);
- return 0;
- }
- load_command = (struct load_command *) hdrbuf;
- symtab_seen = 0;
- for (cmd = 0; cmd < mach_header.ncmds; ++cmd)
- {
- if (load_command->cmd == LC_SYMTAB)
- {
- symtab_seen = 1;
- symtab_command = (struct symtab_command *) load_command;
- *syms_offset = symtab_command->symoff;
- *syms_size = symtab_command->nsyms * sizeof (struct nlist);
- *strs_offset = symtab_command->stroff;
- *strs_size = symtab_command->strsize;
- }
- load_command = (struct load_command *) ((char *) load_command + load_command->cmdsize);
- }
- free (hdrbuf);
- if (!symtab_seen)
- *syms_offset = *syms_size = *strs_offset = *strs_size = 0;
- return 1;
- }
- }
- #endif
-
- error_with_file ("bad format (not an object file) in ", mapelt);
- return 0;
- }
-
- /* Create the info.symdefs for a new member
- by reading the file it is coming from. */
-
- void
- make_new_symdefs (mapelt, archive_indesc)
- struct mapelt *mapelt;
- int archive_indesc;
- {
- int indesc;
- char *name = mapelt->info.name;
- long int syms_offset, strs_offset;
- unsigned int syms_size, strs_size;
- struct nlist *symbols;
- int symcount;
- char *strings;
- register unsigned int i;
- unsigned long int offset;
-
- if (name == 0)
- /* Deleted member. */
- abort ();
-
- {
- indesc = open (mapelt->info.name, 0, 0);
- if (indesc < 0)
- {
- perror_with_name (mapelt->info.name);
- return;
- }
- offset = 0;
- }
-
- if (!read_header_info (mapelt, indesc, offset, &syms_offset, &syms_size, &strs_offset, &strs_size))
- {
- if (mapelt->info.offset == 0)
- close (indesc);
- return;
- }
-
- /* Number of symbol entries in the file. */
- symcount = syms_size / sizeof (struct nlist);
- /* Allocate temporary space for the symbol entries. */
- symbols = (struct nlist *) alloca (syms_size);
- /* Read in the symbols. */
- lseek (indesc, syms_offset + offset, 0);
- if (read (indesc, (char *) symbols, syms_size) != syms_size)
- {
- error_with_file ("premature end of file in symbols of ", mapelt);
- if (mapelt->info.offset == 0)
- (void) close (indesc);
- return;
- }
-
- /* The string table size includes the size word. */
- if (strs_size < sizeof (strs_size))
- {
- error_with_file ("bad string table size in ", mapelt);
- if (mapelt->info.offset == 0)
- (void) close (indesc);
- return;
- }
- strs_size -= sizeof (strs_size);
-
- /* Allocate permanent space for the string table. */
- strings = (char *) xmalloc (strs_size);
-
- /* Read in the strings. */
- lseek (indesc, offset + strs_offset + sizeof strs_size, 0);
- if (read (indesc, strings, strs_size) != strs_size)
- {
- error_with_file ("premature end of file in strings of ", mapelt);
- if (mapelt->info.offset == 0)
- (void) close (indesc);
- return;
- }
-
- (void) close (indesc);
-
- /* Discard the symbols we don't want to mention; compact the rest down. */
- symcount = filter_symbols (symbols, symcount);
-
- mapelt->info.symdefs = (struct symdef *)
- xmalloc (symcount * sizeof (struct symdef));
- mapelt->info.nsymdefs = symcount;
- mapelt->info.string_size = 0;
-
- for (i = 0; i < symcount; ++i)
- {
- unsigned long int stroff = symbols[i].n_un.n_strx - sizeof (strs_size);
- char *symname = strings + stroff;
- if (stroff > strs_size)
- {
- char buf[100];
- sprintf (buf, "ridiculous string offset %lu in symbol %u of ",
- stroff + sizeof (strs_size), i);
- error_with_file (buf, mapelt);
- return;
- }
- mapelt->info.symdefs[i].s.name = symname;
- mapelt->info.string_size += strlen (symname) + 1;
- }
- }
-
- /* Choose which symbol entries to mention in __.SYMDEF;
- compact them downward to get rid of the rest.
- Return the number of symbols left. */
-
- int
- filter_symbols (syms, symcount)
- struct nlist *syms;
- unsigned int symcount;
- {
- struct nlist *from, *to;
- struct nlist *end = syms + symcount;
-
- for (to = from = syms; from < end; ++from)
- if ((from->n_type & N_EXT)
- && (from->n_type != N_EXT || from->n_value != 0))
- *to++ = *from;
-
- return to - syms;
- }
-
-
- /* Update the __.SYMDEF data before writing a new archive. */
-
- void
- update_symdefs (map, archive_indesc)
- struct mapelt *map;
- int archive_indesc;
- {
- struct mapelt *tail;
- int pos;
- register unsigned int i;
- unsigned int len;
- struct symdef *s;
- unsigned long int deleted_strings_size = 0;
-
- nsymdefs = original_num_symdefs;
- num_old_symdefs = original_num_symdefs;
- new_strings_size = old_strings_size;
- if (nsymdefs != 0)
- {
- /* We already had a __.SYMDEF member, so just update it. */
-
- /* Mark as canceled any old symdefs for members being deleted. */
-
- for (tail = map; tail != 0; tail = tail->next)
- {
- if (tail->info.name == 0)
- {
- /* Old member being deleted. Delete its symdef entries too. */
- for (i = 0; i < original_num_symdefs; i++)
- if (old_symdefs[i].offset == tail->info.offset)
- {
- old_symdefs[i].offset = 0;
- --nsymdefs;
- deleted_strings_size
- += strlen (old_strings
- + old_symdefs[i].s.stringoffset) + 1;
- }
- }
- }
-
- /* Compactify old symdefs. */
- {
- register unsigned int j = 0;
- for (i = 0; i < num_old_symdefs; ++i)
- {
- if (j != i)
- old_symdefs[j] = old_symdefs[i];
- if (old_symdefs[i].offset != 0)
- ++j;
- }
- num_old_symdefs -= i - j;
- }
-
- /* Create symdef data for any new members. */
- for (tail = map; tail != 0; tail = tail->next)
- {
- if (tail->info.offset != 0
- || tail->info.name == 0
- || !strcmp (tail->info.name, "__.SYMDEF"))
- continue;
- make_new_symdefs (tail, archive_indesc);
- nsymdefs += tail->info.nsymdefs;
- new_strings_size += tail->info.string_size;
- }
- }
- else
- {
- /* Create symdef data for all existing members. */
-
- for (tail = map; tail != 0; tail = tail->next)
- {
- if (tail->info.name == 0
- || !strcmp (tail->info.name, "__.SYMDEF"))
- continue;
- make_new_symdefs (tail, archive_indesc);
- nsymdefs += tail->info.nsymdefs;
- new_strings_size += tail->info.string_size;
- }
- }
-
- new_strings_size -= deleted_strings_size;
- old_strings_size -= deleted_strings_size;
-
- /* Now we know the size of __.SYMDEF,
- so assign the positions of all the members. */
-
- tail = find_mapelt_noerror (map, "__.SYMDEF");
- tail->info.size = (sizeof (nsymdefs) + (nsymdefs * sizeof (struct symdef))
- + sizeof (new_strings_size) + new_strings_size);
- symdef_mapelt = tail;
-
- pos = SARMAG;
- for (tail = map; tail != 0; tail = tail->next)
- {
- if (tail->info.name == 0)
- /* Ignore deleted members. */
- continue;
- tail->info.new_offset = pos;
- pos += sizeof (struct ar_hdr) + tail->info.size;
- if (tail->info.size & 1)
- ++pos;
- }
-
- /* Now update the offsets in the symdef data
- to be the new offsets rather than the old ones. */
-
- for (tail = map; tail != 0; tail = tail->next)
- {
- if (tail->info.name == 0)
- continue;
- if (tail->info.symdefs == 0)
- /* Member without new symdef data.
- Check the old symdef data; it may be included there. */
- for (i = 0; i < num_old_symdefs; i++)
- {
- if (old_symdefs[i].offset == tail->info.offset)
- old_symdefs[i].offset = tail->info.new_offset;
- }
- else
- for (i = 0; i < tail->info.nsymdefs; i++)
- tail->info.symdefs[i].offset = tail->info.new_offset;
- }
-
- /* Generate new, combined string table and put each string's offset into the
- symdef that refers to it. Note that old symdefs ref their strings by
- offsets into old_strings but new symdefs contain addresses of strings. */
-
- new_strings = (char *) xmalloc (new_strings_size);
- pos = 0;
-
- /* Write the strings of the old symdefs and update the structures
- to contain indices into the string table instead of strings. */
- for (i = 0; i < num_old_symdefs; i++)
- {
- strcpy (new_strings + pos, old_strings + old_symdefs[i].s.stringoffset);
- old_symdefs[i].s.stringoffset = pos;
- pos += strlen (new_strings + pos) + 1;
- }
- if (pos < old_strings_size)
- {
- unsigned int d = old_strings_size - pos;
- /* Correct the string table size. */
- new_strings_size -= d;
- /* Correct the size of the `__.SYMDEF' member,
- since it contains the string table. */
- symdef_mapelt->info.size -= d;
- }
- else if (pos > old_strings_size)
- fatal ("Old archive's string size was %u too small.",
- pos - old_strings_size);
-
- for (tail = map; tail != 0; tail = tail->next)
- if (tail->info.symdefs)
- {
- len = tail->info.nsymdefs;
- s = tail->info.symdefs;
-
- for (i = 0; i < len; i++)
- {
- strcpy (new_strings + pos, s[i].s.name);
- s[i].s.stringoffset = pos;
- pos += strlen (new_strings + pos) + 1;
- }
- }
- if (pos != new_strings_size)
- fatal ("internal error: inconsistency in new_strings_size", 0);
- }
-
- /* Print error message and usage message, and exit. */
-
- void
- usage (s1, s2)
- char *s1, *s2;
- {
- error (s1, s2);
- fprintf (stderr, "\
- Usage: %s [d|m|p|q|r|t|x [[abi [position-name] [cilouv]] archive file...\n",
- program_name);
- exit (1);
- }
-
- /* Print error message and exit. */
-
- void
- fatal (s1, s2)
- char *s1, *s2;
- {
- error (s1, s2);
- exit (1);
- }
-
- /* Print error message. `s1' is printf control string, the rest are args. */
-
- void
- error (s1, s2, s3, s4, s5)
- char *s1, *s2, *s3, *s4, *s5;
- {
- fprintf (stderr, "%s: ", program_name);
- fprintf (stderr, s1, s2, s3, s4, s5);
- fprintf (stderr, "\n");
- }
-
- void
- error_with_file (string, mapelt)
- char *string;
- struct mapelt *mapelt;
- {
- fprintf (stderr, "%s: ", program_name);
- fprintf (stderr, string);
- if (mapelt->info.offset != 0)
- fprintf (stderr, "%s(%s)", archive, mapelt->info.name);
- else
- fprintf (stderr, "%s", mapelt->info.name);
- fprintf (stderr, "\n");
- }
-
- void
- perror_with_name (name)
- char *name;
- {
- extern int errno, sys_nerr;
- extern char *sys_errlist[];
- char *s;
-
- if (errno < sys_nerr)
- s = concat ("", sys_errlist[errno], " for %s");
- else
- s = "unknown error for %s";
- error (s, name);
- }
-
- void
- pfatal_with_name (name)
- char *name;
- {
- extern int errno, sys_nerr;
- extern char *sys_errlist[];
- char *s;
-
- if (errno < sys_nerr)
- s = concat ("", sys_errlist[errno], " for %s");
- else
- s = "cannot open %s";
- fatal (s, name);
- }
-
- /* Return a newly-allocated string whose contents
- concatenate those of S1, S2, and S3. */
-
- char *
- concat (s1, s2, s3)
- char *s1, *s2, *s3;
- {
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
-
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
-
- return result;
- }
-
- #ifndef THINK_C
- /* Like malloc but get fatal error if memory is exhausted. */
-
- char *
- xmalloc (size)
- unsigned int size;
- {
- extern char *malloc ();
- char *result = malloc (size);
- if (result == 0)
- fatal ("virtual memory exhausted", 0);
- return result;
- }
-
- char *
- xrealloc (ptr, size)
- char *ptr;
- unsigned int size;
- {
- extern char *realloc ();
- char *result = realloc (ptr, size);
- if (result == 0)
- fatal ("virtual memory exhausted");
- return result;
- }
-
- #endif
-